package com.hugoo.core.util;

import com.hugoo.core.Conf;
import java.io.*;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.net.PrintCommandListener;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPHTTPClient;
import org.apache.commons.net.ftp.FTPReply;
import org.apache.commons.net.ftp.FTPSClient;
import org.apache.commons.net.io.CopyStreamEvent;
import org.apache.commons.net.io.CopyStreamListener;
import org.apache.commons.net.util.TrustManagerUtils;

/**
 *
 * @author Lovelock.Chan
 */
public class FTP {

    private final static Log log = LogFactory.getLog(FTP.class);
    //use EPSV with IPv4 (default false),因为扩展被动模式(EPSV)仅在IPV6网络中使用，ReadyNAS不支持。
    private boolean printHash = false;
    private long keepAliveTimeout = -1;
    private int controlKeepAliveReplyTimeout = -1;
    private String protocol = null; // SSL protocol
    private String trustmgr = null;
    //代理部分
    private String proxyHost = null;
    private int proxyPort = 80;
    private String proxyUser = null;
    private String proxyPassword = null;
    //应用部分
    private String ftphost = null;
    private int ftport = 21;
    private String ftpuser = null;
    private String ftpasswd = null;
    private FTPClient ftp;
    private boolean isconn;

    public FTP(String sid) {
        _init_para(sid);
        ftp = _init_ftp();
    }

    public boolean upload(String workingDirectory, String filename, File file) {
        log.info("开始FTP数据上传工作@_@");
        isconn = _connect_ftp();
        if (isconn) {
            int i = 0;
            __relogin:
            try {
                i++;
                if (ftp.login(ftpuser, ftpasswd)) {
                    ftp.setBufferSize(1024);
                    //设置上传目录 
                    ftp.changeWorkingDirectory(workingDirectory);
                    ftp.setBufferSize(1024);
                    ftp.setControlEncoding("GBK");
                    //设置文件类型（二进制） 
                    ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
                    FileInputStream fis = new FileInputStream(file);
                    try {
                        ftp.storeFile(filename, fis);
                    } finally {
                        fis.close();
                    }
                    log.info("上传文件【" + filename + "】成功！");
                } else {
                    log.warn("登录FTP服务器时失败。");
                    if (i < 3) {
                        log.info("重试登录【" + i + "】");
                        break __relogin;
                    }
                }
            } catch (IOException ex) {
                log.warn("登录FTP服务器时出现异常。", ex);
                if (i < 3) {
                    log.info("重试登录【" + i + "】");
                    break __relogin;
                }
            } finally {
                try {
                    ftp.disconnect();
                } catch (IOException ex) {
                    log.warn("关闭FTP连接时出现异常。", ex);
                }
            }
        } else {
            log.error("系统无法连接到FTP服务器====不能正常进行数据上传业务。");
            return false;
        }
        return true;
    }

    public boolean download(String ftpPath, File file) {
        log.info("开始FTP数据下载工作@_@");
        isconn = _connect_ftp();
        if (isconn) {
            int i = 0;
            __relogin:
            try {
                i++;
                if (ftp.login(ftpuser, ftpasswd)) {
                    ftp.setBufferSize(1024);
                    //设置文件类型（二进制） 
                    ftp.setFileType(FTPClient.BINARY_FILE_TYPE);
                    FileOutputStream fos = new FileOutputStream(file);
                    try {
                        ftp.retrieveFile(ftpPath, fos);
                    } finally {
                        fos.close();
                    }
                    log.info("下载文件【" + ftpPath + "】成功！");
                    return true;
                } else {
                    log.warn("登录FTP服务器时失败。");
                    if (i < 3) {
                        log.info("重试登录【" + i + "】");
                        break __relogin;
                    }
                }
            } catch (IOException ex) {
                log.warn("登录FTP服务器时出现异常。", ex);
                if (i < 3) {
                    log.info("重试登录【" + i + "】");
                    break __relogin;
                }
            } finally {
                try {
                    ftp.disconnect();
                } catch (IOException ex) {
                    log.warn("关闭FTP连接时出现异常。", ex);
                }
            }
        } else {
            log.error("系统无法连接到FTP服务器====不能正常进行数据下载【" + ftpPath + "】业务。");
            return false;
        }
        return false;
    }

    private void _init_para(String sid) {
        proxyHost = Conf.getBaseProp(sid, Conf.FTP._proxy_server);
        if (TL.isNotEmpty(proxyHost)) {
            proxyPort = TL.parseInt(Conf.getBaseProp(sid, Conf.FTP._proxy_port), 80);
            proxyUser = Conf.getBaseProp(sid, Conf.FTP._proxy_user);
            proxyPassword = Conf.getBaseProp(sid, Conf.FTP._proxy_passwd);
        }
        //FTP信息
        ftphost = Conf.getBaseProp(sid, Conf.FTP._ftp_host);
        if (TL.isNotEmpty(ftphost)) {
            ftport = TL.parseInt(Conf.getBaseProp(sid, Conf.FTP._ftp_port), -1);
            ftpuser = Conf.getBaseProp(sid, Conf.FTP._ftp_user);
            ftpasswd = Conf.getBaseProp(sid, Conf.FTP._ftp_passwd);
        }
        protocol = Conf.getBaseProp(sid, Conf.FTP._ftp_protocol);
        trustmgr = Conf.getBaseProp(sid, Conf.FTP._ftp_trustmgr);
        keepAliveTimeout = TL.parseInt(Conf.getBaseProp(sid, Conf.FTP._ftp_keepAliveTimeout), -1);
        controlKeepAliveReplyTimeout = TL.parseInt(Conf.getBaseProp(sid, Conf.FTP._ftp_controlKeepAliveReplyTimeout), -1);
    }

    private boolean _connect_ftp() {
        try {
            int reply;
            if (ftport > 0) {
                ftp.connect(ftphost, ftport);
            } else {
                ftp.connect(ftphost);
            }
            log.info("Connected to " + ftphost + " on " + (ftport > 0 ? ftport : ftp.getDefaultPort()));
            // After connection attempt, you should check the reply code to verify
            // success.
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
                log.warn("FTP server refused connection.");
                return false;
            }
        } catch (IOException e) {
            if (ftp.isConnected()) {
                try {
                    ftp.disconnect();
                } catch (IOException f) {
                    // do nothing
                }
            }
            log.warn("Could not connect to server.", e);
            return false;
        }
        return true;
    }

    private FTPClient _init_ftp() {
        FTPClient _ftp;
        if (protocol == null) {
            if (proxyHost != null) {
                _ftp = new FTPHTTPClient(proxyHost, proxyPort, proxyUser, proxyPassword);
            } else {
                _ftp = new FTPClient();
            }
        } else {
            FTPSClient ftps;
            if (protocol.equals("true")) {
                ftps = new FTPSClient(true);
            } else if (protocol.equals("false")) {
                ftps = new FTPSClient(false);
            } else {
                String prot[] = protocol.split(",");
                if (prot.length == 1) { // Just protocol
                    ftps = new FTPSClient(protocol);
                } else { // protocol,true|false
                    ftps = new FTPSClient(prot[0], Boolean.parseBoolean(prot[1]));
                }
            }
            _ftp = ftps;
            if ("all".equals(trustmgr)) {
                ftps.setTrustManager(TrustManagerUtils.getAcceptAllTrustManager());
            } else if ("valid".equals(trustmgr)) {
                ftps.setTrustManager(TrustManagerUtils.getValidateServerCertificateTrustManager());
            } else if ("none".equals(trustmgr)) {
                ftps.setTrustManager(null);
            }
        }
        if (printHash) {
            _ftp.setCopyStreamListener(createListener());
        }
        if (keepAliveTimeout >= 0) {
            _ftp.setControlKeepAliveTimeout(keepAliveTimeout);
        }
        if (controlKeepAliveReplyTimeout >= 0) {
            _ftp.setControlKeepAliveReplyTimeout(controlKeepAliveReplyTimeout);
        }
        // suppress login details
        _ftp.addProtocolCommandListener(new PrintCommandListener(new PrintWriter(System.out), true));
        return _ftp;
    }

    private static CopyStreamListener createListener() {
        return new CopyStreamListener() {
            private long megsTotal = 0;

            public void bytesTransferred(CopyStreamEvent event) {
                bytesTransferred(event.getTotalBytesTransferred(), event.getBytesTransferred(), event.getStreamSize());
            }

            public void bytesTransferred(long totalBytesTransferred,
                    int bytesTransferred, long streamSize) {
                long megs = totalBytesTransferred / 1000000;
                for (long l = megsTotal; l < megs; l++) {
                    System.err.print("#");
                }
                megsTotal = megs;
            }
        };
    }
}
